export type CacheObjectOptions<T> = {
  filled: boolean
  valid: boolean
  data: T
  key: string
  persistent?: boolean
  store?: LocalForage | null
}

export default class CacheObject<T> {
  public static create<T>(option?: Partial<CacheObjectOptions<T>>) {
    return new CacheObject(option)
  }

  private readonly key: string
  private readonly persistent: boolean = false
  private filled = false
  private valid = false
  private data: T | null
  private store: LocalForage | null = null

  public constructor(options: Partial<CacheObjectOptions<T>> = {}) {
    this.filled = options.filled === true
    this.valid = options.valid === true
    this.data = options.data || null
    this.persistent = options.persistent === true
    this.key = options.key || 'default'
    this.store = options.store || null
  }

  public isValid() {
    return this.valid
  }

  public isFilled() {
    return this.filled
  }

  public async getValue() {
    return this.data
  }

  public async setValue(data: T) {
    this.data = data
    this.filled = true
    this.valid = true
    await this.saveToStore()
    return this
  }

  public async saveToStore() {
    if (!this.persistent || !this.valid)
      return

    await this.store!.setItem(this.getCacheKey(), this.data)
  }

  public async readFromStore() {
    if (!this.persistent || this.valid)
      return

    const dd = await this.store!.getItem<T>(this.getCacheKey())
    if (!dd)
      return

    try {
      this.data = dd
      this.valid = true
    }
    catch (e) {}
  }

  private getCacheKey() {
    return `xz-cache-${this.key}`
  }
}
